#include <BTextEdit>
#include <BStyle>

#include "MethodFormat.h"

MethodFormat::MethodFormat(const BString& name) : BTextFormat(name)
{
	_treeItem = 0;

	connect(this, Signal_AssetChanged, &MethodFormat::slotAssetChanged);
}
MethodFormat::~MethodFormat()
{

}

void MethodFormat::styled(const BStyle* style)
{

}
void MethodFormat::changed(const BString& text)
{
	BString name;
	BString params;

	_itemMap.clear();
	if (text.empty())
		return;

	int name_end = text.find('(');
	int name_begin = text.find("operator");
	if (name_begin == text.size())
		name_begin = name_end - 1;
	while (name_begin > 0)
	{
		if (isspace(text[name_begin]))
		{
			name_begin++;
			break;
		}
		name_begin--;
	}
	text.substr(name, name_begin, name_end);
	formatKeywords(text, 0, name_begin);

	auto it = _itemMap.insert(name_begin);
	it->range.set(name_begin, name_end);
	it->color.set(50, 160, 60);

	int param_begin = name_end + 1;
	int param_end = text.rfind(')');
	text.substr(params, param_begin, param_end);
	formatKeywords(text, param_begin, param_end);
	formatKeywords(text, param_end, text.size());
}

const BColor* MethodFormat::color(int pos) const
{
	auto it = _itemMap <= pos;
	if (it.valid())
	{
		if (pos < it->range.max())
			return &it->color;
	}
	return 0;
}

int MethodFormat::strideBlock(const BString& text, int pos)
{
	int depth = 0;
	int level = 0;
	while (pos < text.size())
	{
		if (text[pos] == '{')
		{
			level++;
			depth++;
		}
		if (text[pos] == '}')
			level--;
		if (text[pos] == '\n' && depth > 0 && level == 0)
			return pos + 1;
		pos++;
	}
	return pos;
}
void MethodFormat::formatKeywords(const BString& text, int begin, int end)
{
	BString word;
	while (begin < end)
	{
		int pos = text.word(word, begin, end);
		if (word == "void" ||
			word == "bool" ||
			word == "int" ||
			word == "unsigned" ||
			word == "short" ||
			word == "float" ||
			word == "double" ||
			word == "const" ||
			word == "virtual" ||
			word == "inline" ||
			word.beginWith('B'))
		{
			auto it = _itemMap.insert(begin);
			it->color.set(50, 50, 160);
			it->range.set(begin, pos);
		}
		else if (word == "class")
		{
			auto it = _itemMap.insert(begin);
			it->color.set(50, 150, 160);
			it->range.set(begin, pos);
		}
		else if (word == "iterator")
		{
			auto it = _itemMap.insert(begin);
			it->color.set(150, 50, 160);
			it->range.set(begin, pos);
		}
		else
		{
			if (word.isNumber())
			{
				auto it = _itemMap.insert(begin);
				it->color.set(150, 50, 60);
				it->range.set(begin, pos);
			}
			else if (word == "true" || word == "false")
			{
				auto it = _itemMap.insert(begin);
				it->color.set(150, 50, 100);
				it->range.set(begin, pos);
			}
		}
		begin = pos;
	}
}

void MethodFormat::slotAssetChanged(BObject* object, const BValue& value)
{
	BTreeItem* item = value;
	if (_treeItem != item)
	{
		_treeItem = item;
		_dirty = true;
	}
	else
	{
		_dirty = false;
	}
}

